//  Brett Jones
//  PBR Senior Thesis
//  Copyright Brett Jones October 2007

using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using Exocortex.Geometry3D;

namespace PBR
{
    /// <summary>
    /// Renders a scene element
    /// </summary>
    class Renderer
    {
        #region Member Variables

        Scene scene;
        
        #endregion

        #region Member Functions

        public Renderer()
        {
        }

        /// <summary>
        /// Renders the current scene
        /// </summary>
        /// <param name="currScene">The current scene to render</param>
        public void Execute(Scene currScene, ref Bitmap outputImage)
        {
            scene = currScene;
            outputImage = new Bitmap(scene.Painting.BackgroundImage);

            if(scene.Painting.Layers.Count == 0)
            {
                return;
            }

            Rectangle fullImage = new Rectangle(0,0,outputImage.Width,outputImage.Height);

            // Lock the data we are currently working on
            BitmapData outputImageData = outputImage.LockBits(fullImage, ImageLockMode.ReadWrite, outputImage.PixelFormat);
            Layer[] layers = scene.Painting.Layers.ToArray();
            BitmapData colorData;
            BitmapData specData;
            BitmapData heightData;

            float diffuseCoef = scene.Material.DiffuseCoef;
            float ambientCoef = scene.Material.SpecularCoef;
            Color ambient = scene.Material.Ambient;
            int stride = outputImageData.Stride - (outputImageData.Width * 4);
            int stridePlusEight = stride + 8;
            Vector3 uVector;
            Vector3 vVector;
            float hScale = scene.Painting.hScale;
            float vScaleDiv255 = scene.Painting.vScale/255.0f;
            Vector3 accum;
            Vector3 normal;

            foreach (Layer layer in scene.Painting.Layers)
            {
                // Lock the current layers data
                colorData = layer.Color.LockBits(fullImage, ImageLockMode.ReadOnly, outputImage.PixelFormat);
                specData = layer.Spec.LockBits(fullImage, ImageLockMode.ReadOnly, outputImage.PixelFormat);
                heightData = layer.Height.LockBits(fullImage, ImageLockMode.ReadOnly, outputImage.PixelFormat);

                unsafe
                {
                    // Color Ptrs
                    byte* colorPtrPrev = (byte*)colorData.Scan0;
                    byte* colorPtrCurr = (byte*)colorData.Scan0 + stride;
                    byte* colorPtrNext = (byte*)colorData.Scan0 + 2 * stride;

                    // Spec Ptrs
                    byte* specPtrPrev = (byte*)specData.Scan0;
                    byte* specPtrCurr = (byte*)specData.Scan0 + stride;
                    byte* specPtrNext = (byte*)specData.Scan0 + 2 * stride;

                    // Height Ptrs
                    byte* heightPtrPrev = (byte*)heightData.Scan0;
                    byte* heightPtrCurr = (byte*)heightData.Scan0 + stride;
                    byte* heightPtrNext = (byte*)heightData.Scan0 + 2 * stride;

                    // Output Image Ptr
                    byte* outputPtr = (byte*)outputImageData.Scan0 + stride;

                    for (int col = 1; col < outputImage.Height-1; col++)
                    {
                        for (int row = 1; row < outputImage.Width-1; row++)
                        {
                            // Clear accum vector
                            accum = Vector3.FromXYZ(0.0f, 0.0f, 0.0f);

                            uVector = Vector3.FromXYZ(0.0f, ((float)(colorPtrPrev[0]-colorPtrCurr[0])*vScaleDiv255), hScale); 
                            //vVector = Vector3.FromXYZ(-1.0f*hScale, ((float)(

                            outputPtr[0] = 255;
                            outputPtr[1] = 55;
                            outputPtr[2] = 0;
                            outputPtr[3] = 255;

                            // Increment Pointers
                            colorPtrPrev += 4;
                            colorPtrCurr += 4;
                            colorPtrNext += 4;

                            specPtrPrev += 4;
                            specPtrCurr += 4;
                            specPtrNext += 4;

                            heightPtrPrev += 4;
                            heightPtrCurr += 4;
                            heightPtrNext += 4;

                            outputPtr += 4;
                        }
                        // Increment Pointers
                        colorPtrPrev += stridePlusEight;
                        colorPtrCurr += stridePlusEight;
                        colorPtrNext += stridePlusEight;

                        specPtrPrev += stridePlusEight;
                        specPtrCurr += stridePlusEight;
                        specPtrNext += stridePlusEight;

                        heightPtrPrev += stridePlusEight;
                        heightPtrCurr += stridePlusEight;
                        heightPtrNext += stridePlusEight;

                        outputPtr += stridePlusEight;
                    }
                }
                // Unlock the current layers data
                layer.Color.UnlockBits(colorData);
                layer.Spec.UnlockBits(specData);
                layer.Height.UnlockBits(heightData);
            }

            // Unlock the output image
            outputImage.UnlockBits(outputImageData);
            
            return;        
        }

        #endregion

        #region Properties
        #endregion
    }
}
